#ifndef _IO_STREAM_H_
#define _IO_STREAM_H_

#include <iotcp.hpp>

#define	STREAM_READ_ERROR			0x01
#define	STREAM_READ_TIMEOUT			0x02
#define	STREAM_WRITE_ERROR			0x04
#define	STREAM_WRITE_TIMEOUT		0x80

class IoStreamBase : public IoTcpBase
{
public:
	IoStreamBase() {

	}
	virtual ~IoStreamBase() {

	}
public:
	int	async_read(BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		rc_assert(this->safe, S_ERROR)

		//no need try catch
		this->ptr->async_receive(boost::asio::buffer(this->ctx.rptr, this->ctx.rlen),
			safe->wrap(boost::bind(&IoStreamBase::stream_handle_read,
			this,
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred)));

		return S_SUCCESS;
	}

	int	async_write(BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		rc_assert(this->safe, S_ERROR)

			//no need try catch
		this->ptr->async_send(boost::asio::buffer(this->ctx.wptr, this->ctx.wlen),
			safe->wrap(boost::bind(&IoStreamBase::stream_handle_write,
			this,
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred)));

		return S_SUCCESS;
	}
	BUFFER_SIZE sync_read(BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		BUFFER_SIZE rc = S_IOERROR;

		try {
			rc = this->ptr->receive(boost::asio::buffer(buf, size));
		}
		catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_IOERROR;
		}
		return rc;
	}
	BUFFER_SIZE sync_write(BUFFER_PTR buf, BUFFER_SIZE size) {

		rc_assert(this->ptr, S_ERROR)
		BUFFER_SIZE rc = S_IOERROR;

		try {
			rc = this->ptr->send(boost::asio::buffer(buf, size));
		}
		catch (stdexcep err) {
			loge("std::exception:%s", err.what());
			rc = S_IOERROR;
		}
		return rc;
	}
private:
	int stream_handle_read(io_c_error_code ec,size_t rbytes) {

		if (ec) {
			this->StreamEventcb(this->ctx.data, STREAM_READ_ERROR);
		}
		else {
			this->StreamReadcb(this->ctx.data, rbytes);
		}
		return S_SUCCESS;
	}

	int stream_handle_write(io_c_error_code ec, size_t wbytes) {

		if (ec) {
			this->StreamEventcb(this->ctx.data, STREAM_WRITE_ERROR);
		}
		else {
			this->StreamWritecb(this->ctx.data, wbytes);
		}
		return S_SUCCESS;
	}
private:
	virtual void StreamWritecb(void *data, BUFFER_SIZE ulen) = 0;
	virtual void StreamReadcb(void *data, BUFFER_SIZE ulen) = 0;
	virtual void StreamEventcb(void *data, event_id what) = 0;
};

#endif

